"""Creates reports for any details about the elements of a profile"""

from itertools import count
from readers import Profile
import pygame
pygame.init()

def formReportProfile(xAtt, yAtt, elements):
    """Returns the profile formed by a report"""
    completeReport=getCompleteReport(xAtt, yAtt, elements)
    atts, completeReport=completeReport[0], completeReport[1:]
    elements=[dict((str(att), str(value)) for att, value in zip(atts, row))
              for row in completeReport]
    atts=[str(att) for att in atts]
    return Profile(elements, atts, '.', atts)

def htmlify(report):
    """Returns the html table of a report"""
    html='<table border="1">'
    for row in report:
        html+='\n'
        html+='<tr>'
        for item in row:
            html+='\n'
            html+='<td>%s</td>'%(item)
        html+='\n'
        html+='</tr>'
    html+='\n'
    html+='</table>'
    return html

def graph(report):
    """Creates the graph for a one dimensional report"""
    report=[row[:-1] for row in report] #Removing the total
    fore=(0,0,0)
    back=(255,255,255)
    width=(len(report[0])-1)*25+10
    height=(max(item for item in report[1][1:])+3)*10
    surface=pygame.Surface((width, height))
    surface.fill(back)
    pygame.draw.line(surface, fore, (10, 0), (10, height-10))
    pygame.draw.line(surface, fore, (10, height-10), (width, height))
    font=pygame.font.Font(None, 15)
    blit=lambda txt, pos: surface.blit(font.render(txt, 0, fore, back), pos)
    blit(report[1][0], (0,0))
    for y, text in zip(xrange(height-10, 4, -10), count()):
        blit(str(text), (0,y))
    for x, text in zip(xrange(5, width, 25), report[0][1:]):
        blit(text, (x, height-8))
    for x, value in zip(xrange(12, width, 25), report[1][1:]):
        rect=pygame.Rect(x, height-(10+value*10), 13, value*10)
        surface.fill(fore, rect)
    pygame.image.save(surface, 'graph.png')

def getCompleteReport(xAtt, yAtt, elements):
    """Forms the complete textual report with headers"""
    report=baseReport(xAtt, yAtt, elements)
    if yAtt:
        completeReport=report
        completeReport.insert(0, ['\\'.join(str(i) for i in (yAtt, xAtt))])
        for att in getAttList(xAtt, elements):
            completeReport[0].append(att)
        completeReport[0].append('Total')
        for att, row in zip(getAttList(yAtt, elements), count(1)):
            completeReport[row]=[att]+completeReport[row]
        completeReport[-1]=['Total']+completeReport[-1]
    else:
        completeReport=[[0]*(len(report)+1)
                        for i in xrange(2)]
        completeReport[0][0]=xAtt
        completeReport[1][0]='Total Number'
        for value, i in zip(report, count(1)):
            completeReport[1][i]=value
        for x,i in zip(getAttList(xAtt, elements), count(1)):
            completeReport[0][i]=x
        completeReport[0][-1]='Total'
    return completeReport

def baseReport(xAtt, yAtt, elements):
    """Takes the attributes to be used as axes and the elements to be used to
    fill in the report"""
    if yAtt:
        return base2dReport(xAtt, yAtt, elements)
    else:
        return base1dReport(xAtt, elements)

def base2dReport(xAtt, yAtt, elements):
    """When there are attributes along both axes"""
    #This is clumsy, but at least it works for now, so if you wish to mess
    #with it, make sure it passes the tests.
    xAttList=getAttList(xAtt, elements)
    yAttList=getAttList(yAtt, elements)
    report=[[0]*(len(xAttList)+1) for i in xrange(1+len(yAttList))]
    for element in elements:
        #x-columns
        column=xAttList.index(element[xAtt])
        #y-rows
        row=yAttList.index(element[yAtt])
        #Adding
        report[row][column]+=1
        report[row][-1]+=1
        report[-1][column]+=1
        report[-1][-1]+=1
    assert(all(len(row)==len(report[0])) for row in report)
    return report

def base1dReport(xAtt, elements):
    """Simply an attribute along an axis"""
    attList=[element[xAtt] for element in elements]
    xRecord=list(set(attList))
    xRecord.sort()
    return [attList.count(att) for att in xRecord]+[len(attList)]

def getAttList(att, elements):
    """Gets the set of unique values for the element in the given list"""
    #Memoize for speed
    ret=list(set(element[att] for element in elements))
    ret.sort()
    return ret
